using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Quartz;
using System.Text.Json;
using Uantek.Device.Communication.Models;
using Uantek.Device.Communication.Services.Interfaces;
using Uantek.Common.Cache;
using Uantek.Tasks;
using Infrastructure;

namespace Uantek.Device.Communication.Jobs
{
    /// <summary>
    /// 数据持久化任务
    /// </summary>
    [DisallowConcurrentExecution]
    public class DataPersistenceJob : JobBase, IJob
    {
        private readonly ILogger<DataPersistenceJob> _logger;
        private readonly IServiceProvider _serviceProvider;

        public DataPersistenceJob()
        {
            _logger = (ILogger<DataPersistenceJob>)App.GetRequiredService(typeof(ILogger<DataPersistenceJob>));
            _serviceProvider = App.ServiceProvider;
        }

        public async Task Execute(IJobExecutionContext context)
        {
            await ExecuteJob(context, async () =>
            {
                await ExecuteDataPersistenceAsync(context);
            });
        }

        private async Task ExecuteDataPersistenceAsync(IJobExecutionContext context)
        {
            using var scope = _serviceProvider.CreateScope();
            var dataCollectionService = scope.ServiceProvider.GetRequiredService<IDataCollectionService>();

            try
            {
                _logger.LogInformation("开始执行数据持久化任务");

                // 获取任务参数
                var jobDataMap = context.JobDetail.JobDataMap;
                var batchSize = GetJobParameter<int>(jobDataMap, "batchSize", 1000);
                var retentionDays = GetJobParameter<int>(jobDataMap, "retentionDays", 90);
                var enableCompression = GetJobParameter<bool>(jobDataMap, "enableCompression", true);
                var exportFormats = GetJobParameter<string[]>(jobDataMap, "exportFormats", new[] { "JSON" });

                // 1. 批量处理Redis中的临时数据
                var (processedRecords, failedRecords) = await ProcessTemporaryDataAsync(batchSize);

                // 2. 清理过期数据
                await CleanupExpiredDataAsync(retentionDays);

                // 3. 数据压缩和归档
                if (enableCompression)
                {
                    await CompressHistoricalDataAsync();
                }

                // 4. 导出数据报告
                await ExportDataReportsAsync(exportFormats, dataCollectionService);

                _logger.LogInformation($"数据持久化任务执行完成，处理记录数: {processedRecords}，失败记录数: {failedRecords}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "数据持久化任务执行失败");
                throw;
            }
        }

        private async Task<(int processedRecords, int failedRecords)> ProcessTemporaryDataAsync(int batchSize)
        {
            try
            {
                _logger.LogInformation("开始处理临时数据");

                var processedRecords = 0;
                var failedRecords = 0;

                // 获取所有临时数据键
                var temporaryKeys = await Task.Run(() => RedisServer.Cache.Keys("device_temp:*"));
                var batches = temporaryKeys.Chunk(batchSize);

                foreach (var batch in batches)
                {
                    var pipeline = RedisServer.Cache.StartPipe();
                    var dataList = new List<DeviceDataModel>();

                    foreach (var key in batch)
                    {
                        try
                        {
                            var dataJson = await Task.Run(() => RedisServer.Cache.Get(key));
                            if (!string.IsNullOrEmpty(dataJson))
                            {
                                var deviceData = JsonSerializer.Deserialize<DeviceDataModel>(dataJson);
                                if (deviceData != null)
                                {
                                    dataList.Add(deviceData);
                                    
                                    // 移动到持久化存储
                                    var persistentKey = key.Replace("device_temp:", "device_data:");
                                    pipeline.Set(persistentKey, dataJson, TimeSpan.FromDays(90));
                                    pipeline.Del(key);
                                    
                                    processedRecords++;
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, $"处理临时数据失败: {key}");
                            failedRecords++;
                        }
                    }

                    await Task.Run(() => pipeline.EndPipe());

                    // 批量写入数据库（如果需要）
                    if (dataList.Count > 0)
                    {
                        await PersistToDatabase(dataList);
                    }
                }

                _logger.LogInformation($"临时数据处理完成，共处理 {processedRecords} 条记录");
                return (processedRecords, failedRecords);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "处理临时数据失败");
                throw;
            }
        }

        private async Task CleanupExpiredDataAsync(int retentionDays)
        {
            try
            {
                _logger.LogInformation($"开始清理 {retentionDays} 天前的过期数据");

                var cutoffDate = DateTime.Now.AddDays(-retentionDays);
                var cutoffDateString = cutoffDate.ToString("yyyyMMdd");

                // 清理过期的设备数据
                var expiredKeys = await Task.Run(() => RedisServer.Cache.Keys($"device_data:*"));
                var keysToDelete = new List<string>();

                foreach (var key in expiredKeys)
                {
                    // 从key中提取日期信息
                    var keyParts = key.Split(':');
                    if (keyParts.Length >= 3)
                    {
                        var keyDatePart = keyParts[2].Substring(0, Math.Min(8, keyParts[2].Length));
                        if (string.Compare(keyDatePart, cutoffDateString) < 0)
                        {
                            keysToDelete.Add(key);
                        }
                    }
                }

                if (keysToDelete.Count > 0)
                {
                    await Task.Run(() => RedisServer.Cache.Del(keysToDelete.ToArray()));
                    _logger.LogInformation($"清理完成，删除了 {keysToDelete.Count} 个过期数据键");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "清理过期数据失败");
            }
        }

        private async Task CompressHistoricalDataAsync()
        {
            try
            {
                _logger.LogInformation("开始压缩历史数据");

                // 获取需要压缩的历史数据（超过7天的数据）
                var compressionDate = DateTime.Now.AddDays(-7);
                var compressionDateString = compressionDate.ToString("yyyyMMdd");

                var historicalKeys = await Task.Run(() => RedisServer.Cache.Keys($"device_data:*"));
                var keysToCompress = historicalKeys.Where(key =>
                {
                    var keyParts = key.Split(':');
                    if (keyParts.Length >= 3)
                    {
                        var keyDatePart = keyParts[2].Substring(0, Math.Min(8, keyParts[2].Length));
                        return string.Compare(keyDatePart, compressionDateString) < 0;
                    }
                    return false;
                }).ToList();

                var compressedCount = 0;
                foreach (var key in keysToCompress)
                {
                    try
                    {
                        var dataJson = await Task.Run(() => RedisServer.Cache.Get(key));
                        if (!string.IsNullOrEmpty(dataJson))
                        {
                            // 简单的压缩示例（实际应用中可以使用更高效的压缩算法）
                            var compressedData = CompressString(dataJson);
                            var compressedKey = key.Replace("device_data:", "device_compressed:");
                            
                            await Task.Run(() => RedisServer.Cache.Set(compressedKey, compressedData, TimeSpan.FromDays(365)));
                            await Task.Run(() => RedisServer.Cache.Del(key));
                            
                            compressedCount++;
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"压缩数据失败: {key}");
                    }
                }

                _logger.LogInformation($"历史数据压缩完成，压缩了 {compressedCount} 个数据项");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "压缩历史数据失败");
            }
        }

        private async Task ExportDataReportsAsync(string[] exportFormats, IDataCollectionService dataCollectionService)
        {
            try
            {
                _logger.LogInformation("开始导出数据报告");

                var reportDate = DateTime.Now.Date;
                var startTime = reportDate.AddDays(-1); // 导出昨天的数据
                var endTime = reportDate.AddSeconds(-1);

                // 获取所有设备ID
                var deviceKeys = await Task.Run(() => RedisServer.Cache.Keys("device_realtime:*"));
                var deviceIds = deviceKeys.Select(key => key.Replace("device_realtime:", "")).ToList();

                foreach (var format in exportFormats)
                {
                    try
                    {
                        var reportData = new List<DeviceDataModel>();

                        foreach (var deviceId in deviceIds)
                        {
                            var deviceData = await dataCollectionService.GetHistoricalDataAsync(deviceId, startTime, endTime);
                            reportData.AddRange(deviceData);
                        }

                        if (reportData.Count > 0)
                        {
                            var exportResult = await dataCollectionService.ExportDataAsync(
                                "all_devices", startTime, endTime, format);

                            if (exportResult.Success && exportResult.Data != null)
                            {
                                // 保存导出的报告
                                var reportFileName = $"device_report_{startTime:yyyyMMdd}.{format.ToLower()}";
                                var reportKey = $"reports:{reportFileName}";
                                var reportContent = Convert.ToBase64String(exportResult.Data);
                                
                                await Task.Run(() => RedisServer.Cache.Set(reportKey, reportContent, TimeSpan.FromDays(30)));
                                
                                _logger.LogInformation($"导出报告成功: {reportFileName}");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"导出 {format} 格式报告失败");
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "导出数据报告失败");
            }
        }

        private async Task PersistToDatabase(List<DeviceDataModel> dataList)
        {
            try
            {
                // 这里可以实现将数据批量写入数据库的逻辑
                // 例如：写入MySQL、PostgreSQL、InfluxDB等时序数据库
                
                _logger.LogDebug($"批量持久化 {dataList.Count} 条数据到数据库");
                
                // 示例实现：可以在这里调用相应的数据库服务
                // await _databaseService.BulkInsertAsync(dataList);
                
                await Task.CompletedTask;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量持久化数据到数据库失败");
                throw;
            }
        }

        private string CompressString(string input)
        {
            // 简单的压缩实现示例
            // 实际应用中应该使用更高效的压缩算法，如GZip、LZ4等
            try
            {
                var bytes = System.Text.Encoding.UTF8.GetBytes(input);
                using var compressedStream = new System.IO.MemoryStream();
                using var gzipStream = new System.IO.Compression.GZipStream(compressedStream, System.IO.Compression.CompressionMode.Compress);
                gzipStream.Write(bytes);
                gzipStream.Close();
                return Convert.ToBase64String(compressedStream.ToArray());
            }
            catch
            {
                return input; // 压缩失败时返回原始数据
            }
        }

        private T GetJobParameter<T>(JobDataMap jobDataMap, string key, T defaultValue)
        {
            try
            {
                if (jobDataMap.ContainsKey(key))
                {
                    var value = jobDataMap[key];
                    if (value is T directValue)
                    {
                        return directValue;
                    }
                    
                    if (value is string stringValue && !string.IsNullOrEmpty(stringValue))
                    {
                        if (typeof(T) == typeof(string[]))
                        {
                            return (T)(object)JsonSerializer.Deserialize<string[]>(stringValue);
                        }
                        else if (typeof(T) == typeof(bool))
                        {
                            return (T)(object)bool.Parse(stringValue);
                        }
                        else if (typeof(T) == typeof(int))
                        {
                            return (T)(object)int.Parse(stringValue);
                        }
                        else
                        {
                            return (T)Convert.ChangeType(stringValue, typeof(T));
                        }
                    }
                }
                return defaultValue;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, $"解析任务参数 {key} 失败，使用默认值: {defaultValue}");
                return defaultValue;
            }
        }
    }

    /// <summary>
    /// 数据持久化任务配置
    /// </summary>
    public class DataPersistenceJobConfig
    {
        /// <summary>
        /// 批处理大小
        /// </summary>
        public int BatchSize { get; set; } = 1000;

        /// <summary>
        /// 数据保留天数
        /// </summary>
        public int RetentionDays { get; set; } = 90;

        /// <summary>
        /// 是否启用压缩
        /// </summary>
        public bool EnableCompression { get; set; } = true;

        /// <summary>
        /// 导出格式
        /// </summary>
        public string[] ExportFormats { get; set; } = new[] { "JSON", "CSV" };

        /// <summary>
        /// 任务执行间隔（Cron表达式）
        /// </summary>
        public string CronExpression { get; set; } = "0 0 2 * * ?"; // 每天凌晨2点执行

        /// <summary>
        /// 转换为JobDataMap
        /// </summary>
        /// <returns></returns>
        public JobDataMap ToJobDataMap()
        {
            var dataMap = new JobDataMap();
            dataMap.Put("batchSize", BatchSize.ToString());
            dataMap.Put("retentionDays", RetentionDays.ToString());
            dataMap.Put("enableCompression", EnableCompression.ToString());
            dataMap.Put("exportFormats", JsonSerializer.Serialize(ExportFormats));
            return dataMap;
        }
    }
}